#include <stdio.h>
#include <stdarg.h>

#include <hwicodec_common.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#ifdef CONFIG_SINGLE_BS
#include <system/imp_alloc.h>
extern IMPAlloc alloc_vpu_bs;
#endif

void hwicodec_log(hwicodec_t *h, int i_level, const char *psz_fmt, ...)
{
    if(!h || i_level <= h->param.i_log_level) {
        va_list arg;
        va_start( arg, psz_fmt );
        if(h && h->param.pf_log) {
            h->param.pf_log(h->param.module, i_level, psz_fmt, arg);
		} else {
            c_log_default("hwicodec", i_level, psz_fmt, arg);
		}
        va_end(arg);
    }
}

int hwicodec_cal_bufsize(hwicodec_t *h, hwicodec_soc_binfo_t *pbinfo, int width, int height)
{
	int size;

	if (pbinfo->bufsize) {
		if (pbinfo->bufsize == -1) {		/* bssize */
			size = width*height*2 + pbinfo->align;
		} else if (pbinfo->bufsize == 1) {
			size = width*height + pbinfo->align;/*y_ncusize*/
		} else{	/* dmasize */
			size = pbinfo->bufsize;
		}
	} else {	/* other size */
		size = (width+2*pbinfo->padh)*(height+2*pbinfo->padv+pbinfo->reserve_v)+pbinfo->align+pbinfo->disalign;
	}

	return c_align(size, pbinfo->align, pbinfo->disalign);
}

static intptr_t hwicodec_get_align_vaddr(intptr_t buf, hwicodec_soc_binfo_t *pbinfo, int width, int plane)
{
	buf = (buf+pbinfo->align-1)&(~(pbinfo->align-1));
	return buf+(width+2*pbinfo->padh)*((pbinfo->padv)>>plane)+pbinfo->padh*((pbinfo->padv)>>plane);
}

static int hwicodec_get_stride(hwicodec_soc_binfo_t *pbinfo, int width)
{
	return C_ALIGN(width, pbinfo->mbsize)+2*pbinfo->padh;
}

static int hwicodec_get_lines(hwicodec_soc_binfo_t *pbinfo, int height)
{
	return height+2*pbinfo->padv + pbinfo->reserve_v;
}

#if 0
static void dump_binfo(hwicodec_soc_bpool_t *bpool, hwicodec_mmcut_t *pcut)
{
	int i = 0, cnt[C_SOC_VB_MAX] = {0};
	if (!bpool) {
		return;
	}
	for (i = 0; i < bpool->buf_num; i++) {
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].alloc_vaddr=%p\n",
				i, bpool->binfo[i].alloc_vaddr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].alloc_paddr=%p\n",
				i, bpool->binfo[i].alloc_paddr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].alloc_size=%d\n",
				i, bpool->binfo[i].alloc_size);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].align_value=%d\n",
				i, bpool->binfo[i].align_value);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].align_vaddr=%p\n",
				i, bpool->binfo[i].align_vaddr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].align_paddr=%p\n",
				i, bpool->binfo[i].align_paddr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].alloc_size=%d\n",
				i, bpool->binfo[i].alloc_size);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->binfo[%d].tlb_needed=%p\n",
				i, bpool->binfo[i].tlb_needed);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->vbinfo[%d].vb[%d].yptr=%p\n",
				pcut[i].type, cnt[pcut[i].type],
				bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].yptr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->vbinfo[%d].vb[%d].cptr=%p\n",
				pcut[i].type, cnt[pcut[i].type],
				bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].cptr);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->vbinfo[%d].vb[%d].i_stride=%d\n",
				pcut[i].type, cnt[pcut[i].type],
				bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].i_stride);
		hwicodec_log(NULL, C_LOG_DEBUG, "bpool->vbinfo[%d].vb[%d].i_lines=%d\n",
				pcut[i].type, cnt[pcut[i].type],
				bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].i_lines);
		cnt[pcut[i].type]++;
	}
}
#endif

int hwicodec_init_soc_bpool(hwicodec_t *h, hwicodec_soc_binfo_t *pbinfo, hwicodec_mmcut_t *pcut,
		int width, int height, int tlb_needed)
{
	hwicodec_soc_bpool_t *bpool = &h->soc.bpool;
	uint8_t *ptr = (uint8_t *)bpool->buf_base_v;
	int i = 0, cnt[C_SOC_VB_MAX] = {0};

	for (i = 0; i < bpool->buf_num; i++) {
#ifdef CONFIG_SINGLE_BS
		if (pcut[i].type == C_SOC_VB_BS) {
			bpool->binfo[i].alloc_vaddr = (intptr_t)alloc_vpu_bs.info.vaddr;
			bpool->binfo[i].alloc_paddr = (intptr_t)alloc_vpu_bs.info.paddr;
			bpool->binfo[i].alloc_size = alloc_vpu_bs.info.length;
		} else
#endif
		{
			bpool->binfo[i].alloc_vaddr = (intptr_t)ptr;
			bpool->binfo[i].alloc_paddr = h->param.ckvirt_to_phys(bpool->binfo[i].alloc_vaddr);
			bpool->binfo[i].alloc_size = pcut[i].size;
		}
		bpool->binfo[i].align_value = pbinfo[pcut[i].type].align;
		bpool->binfo[i].align_vaddr = hwicodec_get_align_vaddr(bpool->binfo[i].alloc_vaddr,
				&pbinfo[pcut[i].type], width, 0);
		bpool->binfo[i].align_paddr = h->param.ckvirt_to_phys(bpool->binfo[i].align_vaddr);
		bpool->binfo[i].align_size = bpool->binfo[i].alloc_size
			- (bpool->binfo[i].align_vaddr - bpool->binfo[i].alloc_vaddr);;
		bpool->binfo[i].tlb_needed = tlb_needed;

		bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].yptr = bpool->binfo[i].align_vaddr;
		bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].cptr = (intptr_t)(ptr + pcut[i].ysize);
		if (pcut[i].type == C_SOC_VB_ENC) {
			bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].i_stride = width;
		} else {
			bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].i_stride =
				hwicodec_get_stride(&pbinfo[pcut[i].type], width);
		}
		bpool->vbinfo[pcut[i].type].vb[cnt[pcut[i].type]].i_lines =
			hwicodec_get_lines(&pbinfo[pcut[i].type], height);
		ptr += pcut[i].size;
		cnt[pcut[i].type]++;
	}

	if (i != bpool->buf_num) {
		hwicodec_log(h, C_LOG_ERROR, "init buf info num:%d not equal to buf_num:%d\n", i, bpool->buf_num);
		goto err_init_buf_info;
	}

	for (i = 0; i < bpool->vb_num; i++) {
		if (bpool->vbinfo[i].num != cnt[i]) {
			hwicodec_log(h, C_LOG_ERROR, "init vb num:%d not equal to num:%d, i = %d\n",
					cnt[i], bpool->vbinfo[i].num, i);
			goto err_vbinfo_num;
		}
	}
	//dump_binfo(&h->soc.bpool, pcut);

	return 0;

err_vbinfo_num:
err_init_buf_info:
	return -1;
}
